<?php
declare(strict_types=1);

namespace ServerApp\lib\util;

use WebApp\lib\config\Config;

//function tracker(...$arr) {
//    var_dump($arr);
//}

/**
 *
 * @property array list
 */
class ServerHelper{
    private $bin_path = '';
    private $log_path = '';
    private $pid_path = '';
    private $master_name = '';
    private $exec_file = '';

    /**
     *
     */
    private function __construct()
    {
        self::initPhp();
//            if ($const_params) {
//                self::initConst($const_params);
//            }
        self::initErrorHandler();
//            if ($flag) {
//                self::$instance->run();
//            }
//            self::$instance->required();
        $array = debug_backtrace();
        $this->exec_file = end($array)['file'];
        $this->master_name = Config::getConf("name") . "_m1";
        $port = Config::getConf("port");
        $this->bin_path = dirname($this->exec_file) . "/bin/".$port."/";
        $this->log_path = dirname($this->exec_file) . "/log/".$port."/";
        $this->pid_path = dirname($this->exec_file) . "/pid/".$port."/";
    }

    private function run()
    {
        $paths = [
            $this->bin_path,
            $this->log_path,
            $this->pid_path,
        ];

        foreach ($paths as $path) {
            shell_exec("rm -rf $path");
            if (!is_dir($path)) {
                mkdir($path, 0766,true);
            }
        }
        $this->fresh();
        $this->look();
        $this->restart();

        $res = shell_exec("ps -ef | grep docker | grep -v grep");
        if ($res) {
            exit;
        }
    }

    private function fresh(){
        $server_name = SERVER_NAME;
        $content = <<<EOF
#!/usr/bin/env bash
kill -USR1 `ps -ef | grep $this->master_name | grep -v grep | awk '{print $2}'`

str_array=()
function getDir(){
    for element in `ls $1`
    do
        dir_or_file=$1"/"\${element}
        if [ -d \${dir_or_file} ]
        then
            getDir \${dir_or_file}
        else
            str_array[\${#str_array[@]}]=`cat \${dir_or_file}`
        fi  
    done
}
getDir $this->pid_path
for str in \${str_array[@]}
do
    echo \$str
    array=(\${str//|/ })
    num=`ps -ef | wc -l`
    if [ \${num} -lt 50 ]; then
        for var in \${array[@]}
        do
            kill -USR1 \${var}
        done
    else
        for var in \${array[@]}
        do
            docker exec -it $server_name kill -USR1 \${var}
        done
    fi
done
EOF;
        $file_path = $this->bin_path . __FUNCTION__;
        file_put_contents($file_path, $content);
        shell_exec("chmod +x $file_path");
    }

    private function look(){
        $log_path = $this->getLogPath();
        $content = <<<EOF
#!/usr/bin/env bash
if [ $1 ]; then
    num=$1
else
    num=30
fi
tail -f $log_path -n \${num}

EOF;
        $file_path = $this->bin_path . __FUNCTION__;
        file_put_contents($file_path, $content);
        shell_exec("chmod +x $file_path");
    }

    private function restart(){
        $d_root = Config::getConf("docker.root");
        $d_image = Config::getConf("docker.image");
        $root_dir = Config::getConf("root_dir");
        $name = SERVER_NAME . PORT;
        $port = PORT;
        $shell_file = substr($this->exec_file, 0, -4) . "_$port.sh";
        $content = <<<EOF
#!/usr/bin/env bash
num=`ps -ef | wc -l`
if [ \${num} -lt 50 ]; then
    pkill php
    $shell_file
else
    docker exec -it $name pkill php
    docker stop $name;docker rm $name;
    docker run --name=$name -d \
    -v $d_root:$d_root \
    -v /home:/home \
    -v $root_dir:$root_dir \
    -p 0.0.0.0:$port:$port/tcp \
    -p 0.0.0.0:1$port:1$port/tcp \
    $d_image $shell_file;
fi
EOF;
        $file_path = $this->bin_path . __FUNCTION__;
        file_put_contents($file_path, $content);
        shell_exec("chmod +x $file_path");
    }

    private static $instance = null;

    private static function initConst($params = []){
        if (!$params) {
            global $argv;
        } else {
            $argv = $params;
        }
        foreach ($argv as $index => $str) {
            $arr = explode('=', $str);
            if (count($arr) != 2) {
                continue;
            }
            switch ($arr[0]) {
                case "PORT":
                    define("PORT", (int)$arr[1]);
                    break;
                case "CONFIG_PATH":
                    define("CONFIG_PATH", $arr[1]);
                    break;
                case "FUNCTION_PATH":
                    define("FUNCTION_PATH", $arr[1]);
                    break;
                case "SERVER_NAME":
                    define("SERVER_NAME", $arr[1]);
                    break;
                default:
                    die("master input param (PORT && CONFIG_PATH && FUNCTION_PATH && SERVER_NAME) like run.php PORT=80");
            }
        }
        if(!defined('PORT') || !defined('CONFIG_PATH')) {
            die("master input param (must{PORT|CONFIG_PATH} choose{FUNCTION_PATH}) like run.php PORT=80!!");
        }
    }

    private static function initErrorHandler(){
        set_error_handler(function($err_num, $err_str, $err_file, $err_line){
            if (isset($_SERVER['REQUEST_URI'])){
                tracker('$_SERVER', $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI']);
                if ($_POST) tracker('$_POST', $_POST);
            }
            tracker("EEE", join('@', [$err_num, $err_str, $err_file, $err_line]));
        }, E_ALL & ~E_DEPRECATED);

        set_exception_handler(function($e){
            if (isset($_SERVER['REQUEST_URI'])){
                tracker('$_SERVER', $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI']);
                if ($_POST) tracker('$_POST', $_POST);
            }
            tracker("EEE1", (string)$e);
        });
        register_shutdown_function(function () {
            $arr = error_get_last();
            if ($arr) {
                tracker("EEE2", $arr);
            }
        });
    }

    private static function initPhp()
    {
        error_reporting(E_ALL ^ E_DEPRECATED);
        date_default_timezone_set('Asia/Shanghai');
    }

    /**
     * @internal param $parent
     * @param bool $flag
     * @param array $const_params
     */
    public static function init($flag = true, $const_params=[]){
        if (self::$instance === null) {
            self::$instance = new self();
        }
    }

    /**
     *
     */
    public static function getInstance(): ServerHelper
    {
        if (!self::$instance) {
            die("you should init first");
        }
        return self::$instance;
    }

    public function getLogPath() {
        $log_mode = Config::getConf("log.mode");
        switch ($log_mode) {
            default:
            case 'default':
                $date = "all";
                $tmp = "{$this->log_path}{$date}.log";
                break;
            case 'day':
                $date = date("Y-m-d");
                $tmp = "{$this->log_path}{$date}.log";
                break;
            case 'month':
                $date = date("Y-m-d");
                $tmp = "{$this->log_path}{$date}.log";
                break;
        }
        return $tmp;
    }

    /**
     *
     */
    public function getPidPath() {
        return "{$this->pid_path}";
    }

    public function required () {
        if (defined('FUNCTION_PATH')) {
            require_once FUNCTION_PATH . '';
        }
    }

    private $host = null;

    /**
     * @return bool|null|string
     */
    public function getHost(){
        if ($this->host) {
            return $this->host;
        }

        $path = '/home/host';
        if(!is_file($path)){
            $res = shell_exec('curl ifconfig.me/all.json');
            $arr = json_decode($res, true);
            $val = trim($arr['ip_addr']);
            file_put_contents($path, $val);
        }else{
            $val = file_get_contents($path);
        }

        return $val;
    }
}
